<?php
/**
 * 百度ocr基础接口封装（官方的sdk有问题，并且繁琐，新的识别业务走这边）
 */
namespace soa\ocr\baiduOcr;
use soa\check\EnvCheck;
use artisan\http;
use artisan\cache;

class baiduOcr{
    protected static $token = '';//从百度接口获取来的token，百度官方有效期30天，我们每天换一个新的token

    //百度ocr通用文字识别（基础）接口 线上正式参数！！
    protected static $generalBasic = [
        'appId'     => 'OWzX2eyxpbrdV5woHMAHDqEX',
        'appSecret' => 'PmHNWoGFxK89d7VjgtRemN9fwVaGjQCV',
        'apiUrl'    => 'https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic',
    ];

    //百度ocr通用文字识别（带坐标位置信息）接口 线上正式参数！！
    protected static $generalWithLocation = [
        'appId'     => 'OWzX2eyxpbrdV5woHMAHDqEX',//9568854
        'appSecret' => 'PmHNWoGFxK89d7VjgtRemN9fwVaGjQCV',
        'apiUrl'    => 'https://aip.baidubce.com/rest/2.0/ocr/v1/general',
    ];

    //百度ocr高精度文字识别（带坐标位置信息）接口 线上正式参数！！
    protected static $accurateWithLocation = [
        'appId'     => 'OWzX2eyxpbrdV5woHMAHDqEX',//9568854
        'appSecret' => 'PmHNWoGFxK89d7VjgtRemN9fwVaGjQCV',
        'apiUrl'    => 'https://aip.baidubce.com/rest/2.0/ocr/v1/accurate',
    ];

    //百度ocr图像主体检测接口 线上正式参数！！
    protected static $objectDetect = [
        'appId'     => 'OWzX2eyxpbrdV5woHMAHDqEX',//9568854
        'appSecret' => 'PmHNWoGFxK89d7VjgtRemN9fwVaGjQCV',
        'apiUrl'    => 'https://aip.baidubce.com/rest/2.0/image-classify/v1/object_detect',
    ];

    //百度ocr身份证识别接口 线上正式参数！！
    protected static $idCardOCR = [
        'appId'     => 'OWzX2eyxpbrdV5woHMAHDqEX',//9568854
        'appSecret' => 'PmHNWoGFxK89d7VjgtRemN9fwVaGjQCV',
        'apiUrl'    => 'https://aip.baidubce.com/rest/2.0/ocr/v1/idcard',
    ];


    /**
     * 初始化账号
     */
    protected static function init(){
        //81和online_test环境
        if(!EnvCheck::isEnvOnline()){
            //百度ocr通用文字识别（基础）接口
            self::$generalBasic = [
                'appId'     => 'q97rHB2aMGmGiDsrfnLnemhO',
                'appSecret' => 'WERhAisanbKHEvG0pMYvkiWhpfMUYZxy',
                'apiUrl'    => 'https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic',
            ];
            //百度ocr通用文字识别（带坐标位置信息）接口
            self::$generalWithLocation = [
                'appId'     => 'q97rHB2aMGmGiDsrfnLnemhO',
                'appSecret' => 'WERhAisanbKHEvG0pMYvkiWhpfMUYZxy',
                'apiUrl'    => 'https://aip.baidubce.com/rest/2.0/ocr/v1/general',
            ];
            //百度ocr高精度文字识别（带坐标位置信息）接口
            self::$accurateWithLocation = [
                'appId'     => 'q97rHB2aMGmGiDsrfnLnemhO',
                'appSecret' => 'WERhAisanbKHEvG0pMYvkiWhpfMUYZxy',
                'apiUrl'    => 'https://aip.baidubce.com/rest/2.0/ocr/v1/accurate',
            ];
            //百度ocr图像主体检测接口
            self::$objectDetect = [
                'appId'     => 'vr8nvoZDuqU467ycsUKZpLVQ',//10236169
                'appSecret' => '9FUnNwII2NgtUvq0NPjGz2fZHHW7V6H5',
                'apiUrl'    => 'https://aip.baidubce.com/rest/2.0/image-classify/v1/object_detect',
            ];
            //百度ocr身份证识别接口
            self::$idCardOCR = [
                'appId'     => 'CE0tOIPHnR4yIRgCEaoZ3Oom',//9569291
                'appSecret' => 'p8aEbsnCN5qiOWPiezxZGz2rz3tYtuGM',
                'apiUrl'    => 'https://aip.baidubce.com/rest/2.0/ocr/v1/idcard',
            ];
        }
    }

    /**
     * 获取token，存储缓存保留一天
     * @param $appId
     * @param $appSecret
     * @param string $type   GWL=generalWithLocation;GB=generalBasic
     * @return bool|mixed|null|string
     */
    public static function getToken($appId, $appSecret, $type='GB'){
        $cacheKey = date('Y-m-d').'_'.$type;
        self::$token = cache::get($cacheKey);
        if(empty(self::$token)){
            $getTokenUrl = 'https://aip.baidubce.com/oauth/2.0/token';
            $getTokenData = [
                'grant_type'    => 'client_credentials',
                'client_id'     => $appId,
                'client_secret' => $appSecret,
            ];

            $time = time();
            $tokenRetJson = http::get($getTokenUrl, $getTokenData);
            $tokenRetArr = json_decode($tokenRetJson, true);
            if(//获取到token了
                json_last_error() == JSON_ERROR_NONE &&
                !empty($tokenRetJson) &&
                isset($tokenRetArr['access_token']) &&
                $tokenRetArr['access_token']
            ){
                self::$token = $tokenRetArr['access_token'];//有效期30天（存缓存1天）
                cache::set($cacheKey, self::$token, 86400);//缓存保留一天
            }else{//记录错误日志
                logDebug([
                    'timeOut'      => time()-$time,
                    'getTokenData' => $getTokenData,
                    'tokenRetJson' => '$tokenRetJson',
                ], 'getBaiduOcrToken', true);
            }
        }
        return self::$token;
    }

    /**
     * 百度ocr通用文字识别（基础）接口
     * @param $img   //支持两种格式  图片的url全路径，或者图片的文件流
     * @return array
     *
     * 百度计费价格  2017-09-20更新
     * 0<调用次数<=5	0.0050
     * 5<调用次数<=10	0.0045
     * 10<调用次数<=20	0.0040
     * 20<调用次数<=50	0.0035
     * 50<调用次数<=100	0.0030
     * 100<调用次数	0.0025
     *
     */
    public static function generalBasic($img){
        self::init();
        $token = self::getToken(self::$generalBasic['appId'], self::$generalBasic['appSecret'], 'GB');

        if(empty($token)){
            raise(1009, '获取token失败！');
        }

        $apiUrl = self::$generalBasic['apiUrl'].'?access_token='.$token;

        $requestData = [
            'recognize_granularity' => 'big',//是否定位单字符位置big-不定位；默认small-定位
            'language_type'         => 'CHN_ENG',//CHN_ENG、ENG、POR、FRE、GER、ITA、SPA、RUS、JAP、KOR
            'detect_direction'      => 'true',//是否检测图像朝向，默认不检测，即：false。string true、false
            'detect_language'       => 'false',//是否检测语言，默认不检测 string true、false
            'probability'           => 'false',//是否返回识别结果中每一行的置信度string true、false
        ];

        //image和url字段二选一即可
        if(stripos($img, 'http') !== false){//是url
            $requestData['url'] = $img;
        }else{//是文件流
            $requestData['image'] = $img;
        }

        $time = time();
        $retJson = http::post($apiUrl, $requestData);
        $retArr = json_decode($retJson, true);
        if(json_last_error() == JSON_ERROR_NONE && !empty($retArr)){
            return $retArr;
        }else{
            logDebug([
                'timeOut'     => time()-$time,
                'requestData' => $requestData,
                'retJson'     => '$retJson',
            ], 'ocr_generalBasic', true);
            return [];
        }
    }

    /**
     * 百度ocr通用文字识别（带坐标位置信息）接口
     * @param $img   支持两种格式  图片的url全路径，或者图片的文件流
     * @return array
     *
     * 百度计费价格  2017-09-20更新
     * 0<调用次数<=5	    0.0100
     * 5<调用次数<=10	0.0080
     * 10<调用次数<=20	0.0065
     * 20<调用次数<=50	0.0055
     * 50<调用次数<=100	0.0050
     * 100<调用次数	0.0047
     *
     */
    public static function generalWithLocation($img){
        self::init();
        $token = self::getToken(self::$generalWithLocation['appId'], self::$generalWithLocation['appSecret'], 'GWL');

        if(empty($token)){
            raise(1009, '获取token失败！');
        }

        $apiUrl = self::$generalWithLocation['apiUrl'].'?access_token='.$token;

        $requestData = [
            'recognize_granularity' => 'big',//是否定位单字符位置big-不定位；默认small-定位
            'language_type'         => 'CHN_ENG',//CHN_ENG、ENG、POR、FRE、GER、ITA、SPA、RUS、JAP、KOR
            'detect_direction'      => 'true',//是否检测图像朝向，默认不检测，即：false。string true、false
            'detect_language'       => 'false',//是否检测语言，默认不检测 string true、false
            'vertexes_location'     => 'false',//是否返回文字外接多边形顶点位置，不支持单字位置。string true、false
            'probability'           => 'false',//是否返回识别结果中每一行的置信度string	true、false
        ];

        //image和url字段二选一即可
        if(stripos($img, 'http') !== false){//是url
            $requestData['url'] = $img;
        }else{//是文件流
            $requestData['image'] = $img;
        }

        $time = time();
        $retJson = http::post($apiUrl, $requestData);
        $retArr = json_decode($retJson, true);
        if(json_last_error() == JSON_ERROR_NONE && !empty($retArr)){
            return $retArr;
        }else{
            logDebug([
                'timeOut'     => time()-$time,
                'requestData' => $requestData,
                'retJson'     => '$retJson',
            ], 'ocr_generalWithLocation', true);
            return [];
        }
    }

    /**
     * 百度ocr高精度文字识别（带坐标位置信息）接口
     * @param $img   支持两种格式  图片的url全路径，或者图片的文件流
     * @return array
     *
     * 0<调用次数<=5	0.040
     * 5<调用次数<=10	0.034
     * 10<调用次数<=20	0.029
     * 20<调用次数<=50	0.025
     * 50<调用次数<=100	0.022
     * 100<调用次数	0.020
     *
     */
    public static function accurateWithLocation($img){
        self::init();
        $token = self::getToken(self::$accurateWithLocation['appId'], self::$accurateWithLocation['appSecret'], 'AWL');

        if(empty($token)){
            raise(1009, '获取token失败！');
        }

        $apiUrl = self::$accurateWithLocation['apiUrl'].'?access_token='.$token;

        $requestData = [
            'recognize_granularity' => 'big',//是否定位单字符位置big-不定位；默认small-定位
            'language_type'         => 'CHN_ENG',//CHN_ENG、ENG、POR、FRE、GER、ITA、SPA、RUS、JAP、KOR
            'detect_direction'      => 'true',//是否检测图像朝向，默认不检测，即：false。string true、false
            'detect_language'       => 'false',//是否检测语言，默认不检测 string true、false
            'vertexes_location'     => 'false',//是否返回文字外接多边形顶点位置，不支持单字位置。string true、false
            'probability'           => 'false',//是否返回识别结果中每一行的置信度string	true、false
        ];

        //image和url字段二选一即可
        if(stripos($img, 'http') !== false){//是url
            $requestData['image'] = base64_encode(file_get_contents($img));
//            $requestData['url'] = $img;//高精度版本不支持传url
        }else{//是文件流
            $requestData['image'] = $img;
        }

        $time = time();
        $retJson = http::post($apiUrl, $requestData);
        $retArr = json_decode($retJson, true);
        if(json_last_error() == JSON_ERROR_NONE && !empty($retArr)){
            return $retArr;
        }else{
            logDebug([
                'timeOut'     => time()-$time,
                'requestData' => $requestData,
                'retJson'     => '$retJson',
            ], 'ocr_accurateWithLocation', true);
            return [];
        }
    }

    /**
     * 百度ocr图像主体检测接口
     * @param $img   支持两种格式  图片的url全路径，或者图片的文件流
     * @param int $withFace 默认不支持人脸--0
     * @return array
     */
    public static function objectDetect($img, $withFace=0){
        self::init();
        $token = self::getToken(self::$objectDetect['appId'], self::$objectDetect['appSecret'], 'IOD');

        if(empty($token)){
            raise(1009, '获取token失败！');
        }

        $apiUrl = self::$objectDetect['apiUrl'].'?access_token='.$token;

        $requestData = [
            'image'     => base64_encode(file_get_contents($img)),
            'with_face' => $withFace,//number	-	如果检测主体是人，主体区域是否带上人脸部分，0-不带人脸区域，其他-带人脸区域，裁剪类需求推荐带人脸，检索/识别类需求推荐不带人脸。默认取1，带人脸。
        ];

        $time = time();
        $retJson = http::post($apiUrl, $requestData);
        $retArr = json_decode($retJson, true);
        if(json_last_error() == JSON_ERROR_NONE && !empty($retArr)){
            return $retArr;
        }else{
            logDebug([
                'timeOut'     => time()-$time,
                'requestData' => $requestData,
                'retJson'     => '$retJson',
            ], 'ocr_objectDetect', true);
            return [];
        }
    }

    /**
     * 调用百度身份证识别接口，返回识别结果
     * @param $imgPath  图片地址
     * @param bool $isFront   默认true表示识别正面  ；   false表示识别反面
     * @param array $options  其他参数， 默认['detect_direction'=>true]表示支持图片旋转
     * @return array 返回识别效果
     */
    public static function idCardOCR($img, $isFront = true, $options = ['detect_direction'=>'true']){
        self::init();
        $token = self::getToken(self::$idCardOCR['appId'], self::$idCardOCR['appSecret'], 'ICO');

        if(empty($token)){
            raise(1009, '获取token失败！');
        }
        
        $apiUrl = self::$idCardOCR['apiUrl'].'?access_token='.$token;

        $requestData = [
            'detect_direction' => $options['detect_direction'],//	false	boolean	true、false	是否检测图像朝向，默认不检测，即：false。朝向是指输入图像是正常方向、逆时针旋转90/180/270度。可选值包括:
            'id_card_side'     => $isFront ? 'front' : 'back',//	true	string	front、back	front：身份证正面；back：身份证背面
            'image'	           => base64_encode(file_get_contents($img)),//true	string	-	图像数据，base64编码后进行urlencode，要求base64编码和urlencode后大小不超过4M，最短边至少15px，最长边最大4096px,支持jpg/png/bmp格式
            'detect_risk'      => 'false',//	false	string	true,false	是否开启身份证风险类型(身份证复印件、临时身份证、身份证翻拍、修改过的身份证)功能，默认不开启，即：false。可选值:true-开启；false-不开启
        ];

        $time = time();
        $retJson = http::post($apiUrl, $requestData);
        $retArr = json_decode($retJson, true);
        if(
            json_last_error() == JSON_ERROR_NONE &&
            !empty($retArr)
        ){//成功有返回结果的
            return $retArr;
        }else{
            logDebug([
                'timeOut'     => time()-$time,
                'requestData' => $requestData,
                'retJson'     => '$retJson',
            ], 'ocr_idCardOCR', true);
            return [];
        }
    }
}